package api

import (
	"encoding/json"
	"fmt"
	"time"
	"strings"

	"net/http"
	"strconv"

	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/raft"
	pb "github.com/coreos/etcd/raft/raftpb"
	"github.com/gorilla/mux"
	"github.com/rafttest/util"
)



var MultiNodes = make(map[uint64]*multinode)

var 	MultiPeers = make(map[uint64][]raft.Peer)// = []raft.Peer{{1, nil}, {2, nil}, {3, nil}, {4, nil}, {5, nil}, {6, nil}, {7, nil}, {8, nil}, {9, nil}, {10, nil}, {11, nil}, {12, nil}}
var MultiNt = newMultiRaftNetwork() 

var PeersInfo = make(map[uint64]PeerInfo)


func InitNetWork(){
	go func() {
		for {
			select {
				case ms := <-MultiNt.recv():
					for _, m := range ms {
						if peer_info, ok := PeersInfo[m.to]; ok {
//							fmt.Printf("node_id:%v\n", peer_info.node_id)
							MultiNodes[peer_info.node_id].handlerecv(m)	
						}						
					}					
									
				}
			}
	}()
}

func addPeersHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]
	content := vars["content"]
	
	id_int, err := strconv.Atoi(id)
	if err != nil {
		fmt.Println("转换失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}	
	
	peers := strings.Split(content, ",")
	
	peers_int, err := util.StringToUint64(peers)
	if err != nil {
		fmt.Println("转换失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}
	
	addMultiPeers(uint64(id_int), peers_int...)
}


func addMultiPeers(id uint64, peers ...uint64){
	mp := MultiPeers[id]
	for _, peer := range peers {
		mp = append(mp, raft.Peer{peer, nil})
	}
	MultiPeers[id] = mp
	fmt.Println(MultiPeers)
}


func startMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]
	
	id_int, err := strconv.Atoi(id)
	if err != nil {
		fmt.Printf("字符串转换成整数失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}
	
		
	n := startMultiNode(uint64(id_int), MultiNt)
	MultiNodes[uint64(id_int)] = n

	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}


func createGroupHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]
	group_id := vars["group_id"]
	peer_id := vars["peer_id"]


	id_int, err := strconv.Atoi(id)
	if err != nil {
		fmt.Printf("字符串转换成整数失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	group_id_int, err := strconv.Atoi(group_id)
	if err != nil {
		fmt.Printf("字符串转换成整数失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	peer_id_int, err := strconv.Atoi(peer_id)
	if err != nil {
		fmt.Printf("字符串转换成整数失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	n := MultiNodes[uint64(id_int)]
	c := &raft.Config{
		ID:              uint64(peer_id_int),
		ElectionTick:    10,
		HeartbeatTick:   1,
		//Storage:         raft.NewMemoryStorage(),
		MaxSizePerMsg:   1024 * 1024,
		MaxInflightMsgs: 256,

	}

	PeersInfo[uint64(peer_id_int)] = PeerInfo{node_id: uint64(id_int), group_id: uint64(group_id_int)}
	

	n.createGroup(uint64(group_id_int), c, MultiPeers[uint64(group_id_int)])

}

func stopMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	groupId := vars["id"]

	fmt.Printf("stopNode Request, node_id:%v\n", groupId)

	groupId_int, _ := strconv.Atoi(groupId)


	mn, ok := getMultiNode(uint64(groupId_int))
	if !ok {
		fmt.Printf("get Node failure, node not exist\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	mn.Stop()

	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func restartMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	node_id := vars["node_id"]

	fmt.Printf("restartNode Request, node_id:%v\n", node_id)

	node_id_int, err := strconv.Atoi(node_id)
	if err != nil {
		fmt.Printf("字符串转换成整数失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}
	fmt.Println(node_id_int)

	/*n := getNode(node_id_int)
	if n == nil {
		fmt.Printf("get Node failure, node not exist\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	n.restart()
	*/
	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func pauseMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	node_id := vars["node_id"]

	fmt.Printf("restartNode Request, node_id:%v\n", node_id)

	node_id_int, err := strconv.Atoi(node_id)
	if err != nil {
		fmt.Printf("字符串转换成整数失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}
	fmt.Println(node_id_int)

	/*n := getNode(node_id_int)
	if n == nil {
		fmt.Printf("get Node failure, node not exist\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	n.pause()
	*/

	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func resumeMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	node_id := vars["node_id"]

	fmt.Printf("restartNode Request, node_id:%v\n", node_id)

	node_id_int, err := strconv.Atoi(node_id)
	if err != nil {
		fmt.Printf("字符串转换成整数失败")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	if len(nodes) < node_id_int {
		fmt.Printf("node_id out of bound\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	fmt.Println(node_id_int)
	/*
		n := getNode(node_id_int)
		if n == nil {
			fmt.Printf("get Node failure, node not exist\n")
			util.Response(nil, http.StatusBadRequest, resp)
			return
		}

		n.resume()
	*/
	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func addMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]
	groupId := vars["group_id"]
	nodeId := vars["node_id"]

	fmt.Printf("addMultiNodeHandler Request, groupId:%v node_id:%v\n", groupId, nodeId)

	id_int, _ := strconv.Atoi(id)
	groupId_int, _ := strconv.Atoi(groupId)
	nodeId_int, _ := strconv.Atoi(nodeId)

	addMultiPeers(uint64(groupId_int), uint64(nodeId_int))
	peers, ok := MultiPeers[uint64(groupId_int)]
	if !ok {
		fmt.Printf("addMultiNodeHandler get groupId%v all peers error.\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}
	fmt.Printf("addMultiNode peers: %v\n", peers)

	n := MultiNodes[uint64(id_int)]
	c := &raft.Config{
		ID:              uint64(nodeId_int),
		ElectionTick:    10,
		HeartbeatTick:   1,
		//Storage:         raft.NewMemoryStorage(),
		MaxSizePerMsg:   1024 * 1024,
		MaxInflightMsgs: 256,
	}

	PeersInfo[uint64(nodeId_int)] = PeerInfo{node_id: uint64(id_int), group_id: uint64(groupId_int)}
	n.createGroup(uint64(groupId_int), c, peers)

	cc := pb.ConfChange{
		Type: pb.ConfChangeAddNode,
		NodeID: uint64(nodeId_int),
		Context: []byte(nodeId),
	}

	for _, peer := range peers {
		if peer.ID == uint64(nodeId_int) {
			continue
		}
		mn, ok := getMultiNode(peer.ID)
		if !ok {
			fmt.Printf("getMultiNode groupId:%v peer.ID%v failed.\n", groupId_int, peer.ID)
			util.Response(nil, http.StatusBadRequest, resp)
			return
		}

		if err := mn.ProposeConfChange(context.TODO(), uint64(groupId_int), cc); err != nil {
			fmt.Printf("ProposeConfChange groupId:%v nodeId:%v\n error.", groupId_int, nodeId_int)
		}
	}

	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func removeGroupHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]
	groupId := vars["groupId"]

	fmt.Printf("removeMultiNode Request, id:%v  groupId:%d\n", id ,groupId)

	id_int, _ := strconv.Atoi(id)
	groupId_int, _ := strconv.Atoi(groupId)

	mn, ok := getMultiNode(uint64(id_int))
	if !ok {
		fmt.Printf("get Node failure, node not exist\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	if err := mn.removeGroup(uint64(groupId_int)); err != nil {
		fmt.Printf("[groupId:%d]removeGroup failure\n", groupId_int)
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func proposeMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	groupId := vars["group_id"]
	data := vars["data"]

	fmt.Printf("proposeMultiNode Request, groupId:%v data:%v\n", groupId, data)

	m := make(map[string]string)
	m["data"] = data
	m["time"] = fmt.Sprintf("%v", time.Now())

	json_data, err := json.Marshal(m)
	if err != nil {
		fmt.Printf("data json Marshal error\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	groupId_int, _ := strconv.Atoi(groupId)

	fmt.Println("[proposeMultiHandler] groupId:%v,  json_data:%v\n", groupId_int, json_data)

	mn, ok := getMultiNode(uint64(groupId_int))
	if !ok {
		fmt.Printf("get Node failure, node not exist\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	err = mn.Propose(context.TODO(), uint64(groupId_int), json_data)
	if err != nil {
		fmt.Printf("err:%v\n", err)
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func snapshotMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	groupId := vars["group_id"]
	groupId_int, _ := strconv.Atoi(groupId)

	//data 从哪里获得
	data := []byte("somedata")
	cs := &pb.ConfState{Nodes: []uint64{1, 2, 3}}

	fmt.Printf("snapshotMultiNode groupId:%v MultiPeers:%v\n", groupId_int, MultiPeers)

	peers, ok := MultiPeers[uint64(groupId_int)]
	if !ok {
		fmt.Printf("Get groupId(%v) peers error.", groupId_int)
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	var success bool
	var mnode *multinode
	for _, peer := range peers {
		mn, ok := getMultiNode(peer.ID)
		if ok {
			success = true
			mnode = mn
			break
		}
	}
	if !success {
		fmt.Printf("Get groupId(%v) peer error.", groupId_int)
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	leadId := mnode.Status(uint64(groupId_int)).Lead
	nodeLead, ok := getMultiNode(leadId)
	if !ok {
		fmt.Printf("snapshotAppendHandler getMultiNode failed\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	fmt.Printf("---------->>>>> snapshotAppendHandler leadId:%d Applied:%d\n", leadId, nodeLead.Status(uint64(groupId_int)).Applied)
	snap, err := nodeLead.storage[uint64(leadId)].CreateSnapshot(nodeLead.Status(uint64(groupId_int)).Applied, cs, data)
	if err != nil {
		fmt.Printf("CreateSnapshot err !!!!!!!!!!!!!!!\n")
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	//save snap
	fmt.Printf("snopshotAppend snap:%v\n", snap)

	//Applied
	nodeLead.storage[uint64(leadId)].Compact(nodeLead.Status(uint64(groupId_int)).Applied)

	resp.Header().Set("Content-Type", "Application/json")
	util.Response(nil, http.StatusOK, resp)
}

func dumpAllMultiNodeHandler(resp http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	groupId := vars["group_id"]
	groupId_int, _ := strconv.Atoi(groupId)

	peers, ok := MultiPeers[uint64(groupId_int)]
	if !ok {
		fmt.Printf("Get groupId:%v all peers error.\n", groupId_int)
		util.Response(nil, http.StatusBadRequest, resp)
		return
	}

	fmt.Printf("Peers: %v\nMultiNodes:%v\n", peers, MultiNodes)
	fmt.Printf("\n>>>>>>>>>>> groupId: %v begin <<<<<<<<<<<<<\n", groupId)
	for _, peer := range peers {
		mn, ok := getMultiNode(PeersInfo[peer.ID].node_id)
		if !ok {
			fmt.Printf("getMultiNode groupId:%v peer.ID:%v error.\n", groupId_int, peer.ID)
			util.Response(nil, http.StatusBadRequest, resp)
			return
		}

		fmt.Printf("------------id: %v begin --------------\n", peer.ID)
		fmt.Printf("state: %v\n", mn.state.String())
		fmt.Printf("Status(): %v\n", mn.Status(uint64(groupId_int)).String())
		fmt.Printf("------------id: %v end ------------- \n\n", peer.ID)
	}
	fmt.Printf(">>>>>>>>>>> groupId: %v end   <<<<<<<<<<<<<\n\n", groupId)
}

func getMultiNode(groupId uint64) (*multinode, bool) {
	if v, ok := MultiNodes[groupId]; ok {
		return v, true
	}

	return nil, false
}
